<template>
  <div class="tts-container">
    <div class="content-wrapper">
      <!-- 左侧内容区 -->
      <div class="left-content">
        <div class="header">
          <h1 class="title">文本转语音</h1>
          <a-tooltip placement="top">
            <template #title>
              输入文本后点击生成按钮进行语音转换
            </template>
            <question-circle-outlined class="help-icon" />
          </a-tooltip>
        </div>
        <a-textarea v-model:value="text" :rows="16" placeholder="请输入要转换的文本" class="text-input" :maxlength="5000"
          :disabled="isGenerating" />
        <div class="text-counter">
          <span class="counter">{{ text.length }}/5000</span>
        </div>
        <div class="generate-button-wrapper">
          <a-button type="primary" class="generate-button" :disabled="!text.trim()"
            :class="{ 'disabled-button': !text.trim() }" @click="handleGenerate" :loading="isGenerating">
            生成语音
          </a-button>
        </div>
        <!-- 之后需要切换为音频播放，和调节音量，和具备下载音频的功能 -->
        <div class="player-controls">
          <!-- 播放按钮和 -->
          <div class="player-left">
            <pause-circle-outlined v-if="isPlaying && currentPlayingType === 'main'" class="play-pause-icon"
              @click="togglePlay" :class="{ 'disabled': isGenerating }" />
            <play-circle-outlined v-else class="play-pause-icon" @click="togglePlay"
              :class="{ 'disabled':  isGenerating }" />
            <span class="time-display">{{ currentTime }}/{{ duration }}</span>
          </div>
          <!-- 生成的音频时长进度条 -->
          <div class="progress-bar">
            <a-slider v-model:value="progress" :min="0" :max="100" :disabled="!hasAudio" :tooltip-open="false"
              @change="handleProgressChange" />
          </div>
          <div class="player-right">
            <!-- 倍速调节部分 -->
            <a-select v-model:value="speedNumber" style="width: 90px" size="small" class="custom-select">
              <a-select-option v-for="item in speedDisplay" :key="item.value" :value="item.value">
                {{ item.label }}
              </a-select-option>
            </a-select>
            <!-- 音量控制模块 -->
            <div class="volume-control">
              <sound-outlined class="volume-icon" />
              <div class="volume-slider-container">
                <div class="volume-slider-wrapper">
                  <a-slider v-model:value="volume" :min="0" :max="100" vertical class="volume-slider" />
                </div>
              </div>
            </div>
            <!-- 下载模块 -->
            <a-tooltip placement="top">
              <template #title>
                下载语音文件
              </template>
              <download-outlined class="download-icon" @click="downloadAudio" :class="{ 'disabled': isGenerating }" />
            </a-tooltip>
          </div>
        </div>
      </div>
      <!-- 右侧功能区 -->
      <div class="right-sidebar">
        <div class="tab-navigation">
          <a-button v-for="tab in tabs" :key="tab.key" type="text" class="tab-button" :class="[
              currentTab === tab.key ? 'active-tab' : 'inactive-tab'
            ]" @click="currentTab = tab.key">
            {{ tab.label }}
          </a-button>
        </div>
        <!-- 音色模块 -->
        <div v-show="currentTab === 'voice'">
          <div class="clone-voice-banner" @click="$router.push({ name: 'VoiceLibrary', query: { openAddModal: true } })"
            style="cursor: pointer">
            <h3 class="banner-title">新建克隆声音</h3>
            <p class="banner-description">生成你自己的声音</p>
          </div>
          <div class="voice-library-title">
            <h3>你的语音库</h3>
          </div>
          <!-- 自定义声音显示的下拉框 -->
          <div class="voice-dropdown-container">
            <div class="voice-dropdown" :class="{ selected: selectedVoice }">
              <div class="dropdown-content" @click="!isGenerating && (isDropdownOpen = !isDropdownOpen)"
                :class="{ 'disabled': isGenerating }">
                <span class="dropdown-text">{{ selectedVoice || '选择音色' }}</span>
                <div class="dropdown-icons">
                  <close-circle-outlined v-if="selectedVoice" class="clear-icon" @click.stop="clearSelectedVoice" />
                  <down-outlined :class="{ 'rotate-icon': isDropdownOpen }" />
                </div>
              </div>
            </div>
            <div v-if="isDropdownOpen" class="dropdown-options">
              <div v-if="voiceOptions.length === 0" class="dropdown-option empty-option">
                暂无可用的克隆语音
              </div>
              <div v-else v-for="option in voiceOptions" :key="option" class="dropdown-option"
                @click="selectVoice(option)">
                <div class="option-content">
                  <span class="option-text">{{ option }}</span>
                </div>
              </div>
            </div>
          </div>
          <div class="voice-library-title">
            <h3>音色库</h3>
          </div>
          <div class="voice-grid">
            <div v-for="voice in voices" :key="voice.voiceId" class="voice-card"
              :class="{ 'selected-voice': selectedVoice === voice.voiceName }"
              @click.stop="selectVoice(voice.voiceName)">
              <div class="card-content">
                <div v-if="selectedVoice === voice.voiceName" class="selected-badge">
                  已选
                </div>
                <div class="voice-tag-container">
                  <span class="voice-tag">
                    {{ voice.voiceName }}
                  </span>
                </div>
                <div class="voice-name">{{ voice.shortDescription }}</div>
                <div class="play-button" @click.stop="playPreviewAudio(voice)">
                  <pause-circle-outlined v-if="isPlaying && currentPlayingId === voice.voiceId" class="play-icon" />
                  <play-circle-outlined v-else class="play-icon" />
                </div>
              </div>
              <img :src="voice.shortDescription?.charAt(0) === '女' ? girl : boy" class="card-background" alt="voice background" />
            </div>
          </div>
        </div>
        <!-- 设置模块 -->
        <div v-show="currentTab === 'setting'" class="setting-module">
          <div class="setting-section">
            <h3 class="section-title">语音设置</h3>
            <div class="setting-item">
              <div class="speed-control">
                <div class="speed-header">
                  <div class="speed-title">
                    <span class="label">语速</span>
                    <a-tooltip placement="right" title="调整生成语音播放的语速">
                      <QuestionCircleOutlined class="help-icon" />
                    </a-tooltip>
                  </div>
                  <span class="speed-value">{{ speedValue }}x</span>
                </div>
                <a-slider v-model:value="speedValue" :min="0.5" :max="2" :step="0.1" :marks="speedMarks"
                  class="custom-slider" />
              </div>
            </div>
          </div>
          <div class="setting-section">
            <h3 class="section-title">输出设置</h3>
            <div class="setting-item">
              <span class="setting-label">输出格式</span>
              <a-select v-model:value="outputFormat" class="setting-select">
                <a-select-option value="mp3">MP3</a-select-option>
                <a-select-option value="wav">WAV</a-select-option>
              </a-select>
            </div>
          </div>
        </div>
        <!-- 历史模块 -->
        <div v-show="currentTab === 'history'" class="history-module">
          <div class="history-list">
            <div v-for="record in historyRecords" :key="record.id" class="history-item">
              <div class="history-content">
                <div class="history-text">{{ record.inputText }}</div>
                <div class="history-info">
                  <span class="history-time">{{ record.createTime }}</span>
                  <span class="history-voice">{{ record.voiceName }}</span>
                </div>
              </div>
              <div class="history-actions">
                <pause-circle-outlined v-if="isPlaying && currentPlayingId === record.id" class="history-action-icon"
                  @click="handleHistoryAudioPlay(record)" />
                <play-circle-outlined v-else class="history-action-icon" @click="handleHistoryAudioPlay(record)" />
                <download-outlined class="history-action-icon" @click="handleHistoryDownload(record)" />
                <!-- 添加 Popconfirm 确认框 -->
                <a-popconfirm title="确定要删除这条记录吗？" ok-text="确认" cancel-text="取消"
                  @confirm="!isGenerating && handleDeleteHistory(record.id)" :disabled="isGenerating">
                  <template #icon><question-circle-outlined style="color: red" /></template>
                  <delete-outlined class="delete" />
                </a-popconfirm>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
  import { ref, computed, watch, onUnmounted, onMounted } from 'vue';
  import {
    QuestionCircleOutlined,
    PlayCircleOutlined,
    PlayCircleFilled,
    PauseCircleOutlined,
    SoundOutlined,
    DownloadOutlined,
    DownOutlined,
    CloseCircleOutlined,
    DeleteOutlined,
    EditOutlined,
  } from '@ant-design/icons-vue';

  import { message } from 'ant-design-vue';
  import { getVoiceList, generateVoice, getHistory, deleteHistory, getCloneStatus } from '@/api/TextToSpeech';
  import girl from'@/assets/images/girl.webp';
  import boy from'@/assets/images/boy.webp';
  // 获取语音列表
  onMounted(async () => {
    try {
      const res = await getVoiceList();
      console.log(res.data.list);
      
      presetVoices.value = res.data.list.filter(voice => voice.voiceType === 'system');
      userVoices.value = res.data.list.filter(voice => voice.voiceType === 'clone');
      //获取历史记录的数据
      const response = await getHistory();
      
      historyRecords.value = response.data.list;
      console.log(res);
    } catch (error) {
      console.error('获取语音列表失败:', error);

    }
  });

  // 设置语速模块
  const speedValue = ref(1);
  const speedMarks = {
    0.5: '0.5x',
    0.7: '0.7x',
    1.0: '1.0x',
    1.2: '1.2x',
    1.5: '1.5x',
    1.7: '1.7x',
    2.0: '2.0x'
  };
  // 调节倍速播放的模块
  const speedNumber = ref(1.0)
  const speedDisplay = [
    { value: 2.0, label: '2.0x' },
    { value: 1.5, label: '1.5x' },
    { value: 1.25, label: '1.25x' },
    { value: 1.0, label: '1.0x' },
    { value: 0.75, label: '0.75x' },
    { value: 0.5, label: '0.5x' }
  ];
  const text = ref('');//文本内容
  const isPlaying = ref(false);//控制整个播放按钮

  const progress = ref(0);//音频时间进度条的控制
  const volume = ref(50);//音量大小的控制
  const currentTab = ref('voice');//当前导航栏标签的切换
  // 设置区域相关的响应式数据
  const pitch = ref(0);
  const outputFormat = ref('wav');
  //监管音频播放的相关数据
  const currentAudio = ref(null);
  const currentPlayingType = ref(null);
  const currentPlayingId = ref(null); // 当前正在播放的音频ID
  const audioPlayer = ref(null); // 音频播放器实例
  // 停止所有音频播放
  const stopAllAudio = () => {
    // 停止当前正在播放的音频
    if (currentAudio.value) {
      currentAudio.value.pause();
      currentAudio.value = null;
    }
    // 重置所有音频播放器状态
    if (audioElement.value) {
      audioElement.value.pause();
      audioElement.value.currentTime = 0;
    }
    if (audioPlayer.value) {
      audioPlayer.value.pause();
      audioPlayer.value.currentTime = 0;
    }
    // 重置所有播放状态
    isPlaying.value = false;
    currentPlayingId.value = null;
    currentPlayingType.value = null;
  };

  // 音频相关
  const audioElement = ref(null);
  const audioUrl = ref('');
  const currentTime = ref('00:00');
  const duration = ref('00:00');
  const hasAudio = ref(false);
  // 生成音频的相关数据
  const isGenerating = ref(false);

  const handleGenerate = async () => {
    if (!text.value.trim()) return;
    if (!selectedVoiceId.value) {
      message.warning('请选择音色',1);
      return;
    }

    isGenerating.value = true;
    message.loading('正在生成音频，请稍候...', 0);
    try {
      const voiceData = {
        text: text.value,
        id: selectedVoiceId.value,
        speed: speedValue.value,
        pitch: 1,
        format: outputFormat.value
      };
   console.log(voiceData);
   
      const res = await generateVoice(voiceData);
      const recordId = res.data.recordId;
      console.log(recordId);
      let retryCount = 0;
      const maxRetries = 30; // 最大轮询次数，约1分钟
      const pollingInterval = 2000; // 轮询间隔2秒

      // 轮询检查生成进度
      const checkProgress = async () => {
        try {
          if (retryCount >= maxRetries) {
            message.destroy();
            message.error('生成音频超时，请重试',1);
            isGenerating.value = false;
            return;
          }

          const statusRes = await getCloneStatus(recordId);
          
          const progress = statusRes.data.progress;
          console.log(progress);
          
          if (progress < 100) {
            retryCount++;
            // 使用setTimeout代替直接调用，增加轮询间隔
            setTimeout(checkProgress, pollingInterval);
          } else {
            fetchHistory(recordId);
          }
        } catch (error) {
          console.error('检查生成进度失败:', error);
          message.destroy();
          message.error('生成音频失败，请重试',1);
          isGenerating.value = false;
        }
      };

      // 开始检查进度
      checkProgress();
    } catch (error) {
      console.error('生成语音失败:', error);
    }
  };
  // 获取新的历史记录
  const fetchHistory = async (recordId) => {
    try {
      const res = await getHistory();
      console.log(res);
      
      // 从列表中找到对应recordId的音频数据，并确保类型匹配
      const audioData = res.data.list.find(item => {
        return item.id === recordId 
      });
      console.log(audioData);
      historyRecords.value = res.data.list;
      
      if (audioData) {
        audioUrl.value = audioData.audioUrl;

        // 初始化音频实例并预加载
        initAudioElement(audioUrl.value);
        // 立即格式化并显示音频时长
        duration.value = formatTime(audioData.duration / 1000); // 将毫秒转换为秒
        currentTime.value = '00:00'; // 重置当前播放时间
        hasAudio.value = true;
      
        message.destroy();
        message.success('生成音频成功',1);
        isGenerating.value = false;
      } else {
        message.destroy();
        message.error('未找到对应的音频数据，请重试',1);
        isGenerating.value = false;
      }
    } catch (error) {
      console.error('获取历史记录失败:', error);
      message.destroy();
      message.error('获取历史记录失败，请重试');
      isGenerating.value = false;
    }
  };



  // 更新音频进度的函数
  const updateProgress = () => {
    if (!audioElement.value) return;
    const current = audioElement.value.currentTime;
    const total = audioElement.value.duration;
    progress.value = Math.min((current / total) * 100, 100);
    currentTime.value = formatTime(current);
    duration.value = formatTime(total);
  };

  // 格式化时间函数
  const formatTime = (time) => {
    if (!time || isNaN(time)) return '00:00';
    const minutes = Math.floor(time / 60);
    const seconds = Math.floor(time % 60);
    return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
  };

  // 节流函数
  const throttle = (fn, delay) => {
    let lastTime = 0;
    let rafId = null;
    return function (...args) {
      const now = Date.now();
      if (now - lastTime >= delay) {
        if (rafId) {
          cancelAnimationFrame(rafId);
        }
        rafId = requestAnimationFrame(() => {
          fn.apply(this, args);
          lastTime = now;
          rafId = null;
        });
      }
    };
  };

  // 节流后的更新进度函数
  const throttledUpdateProgress = throttle(updateProgress, 50);



  // 音频加载完成的处理函数
  const handleLoadedMetadata = () => {
    if (audioElement.value) {
      duration.value = formatTime(audioElement.value.duration);
    }
  };

  // 音频结束处理函数
  const handleAudioEnded = () => {
    isPlaying.value = false;
    currentPlayingType.value = null;
    currentPlayingId.value = null;
    currentAudio.value = null;
    progress.value = 100;
    currentTime.value = duration.value;
  };
  // 音频错误处理函数
  const handleAudioError = (e) => {
    console.error('音频加载失败:', e);
    message.error(`音频加载失败`,1);
  };

  // 创建和初始化音频实例
  const initAudioElement = (url) => {
    try {
      // 清理现有音频实例
      if (audioElement.value) {
        audioElement.value.pause();
        audioElement.value.removeEventListener('timeupdate', throttledUpdateProgress);
        audioElement.value.removeEventListener('ended', handleAudioEnded);
        audioElement.value.removeEventListener('loadedmetadata', handleLoadedMetadata);
        audioElement.value.removeEventListener('error', handleAudioError);
        audioElement.value.src = '';
      }

      // 创建新的音频实例
      audioElement.value = new Audio();
      audioElement.value.preload = 'auto';
      audioElement.value.volume = volume.value / 100;
      audioElement.value.playbackRate = speedNumber.value;
      audioElement.value.src = url;

      // 添加事件监听
      audioElement.value.addEventListener('loadedmetadata', handleLoadedMetadata);
      audioElement.value.addEventListener('timeupdate', throttledUpdateProgress);
      audioElement.value.addEventListener('ended', handleAudioEnded);
      audioElement.value.addEventListener('error', handleAudioError);

      // 加载音频
      audioElement.value.load();
    } catch (error) {
      console.error('初始化音频实例失败:', error);
      message.error('音频加载失败',1);
    }
  };


  // 播放/暂停控制
  const togglePlay = () => {
    if (!hasAudio.value || !audioElement.value ){
      message.warning('请先生成音频',1);
      return;
    }  
    if(isGenerating.value){
      message.warning('正在生成音频，请稍候',1);
      return; 
    }

    if (isPlaying.value && currentPlayingType.value === 'main') {
      // 暂停播放
      audioElement.value.pause();
      isPlaying.value = false;
    } else {
      // 开始或恢复播放
      audioElement.value.play().catch(error => {
        console.error('播放音频失败:', error);
        message.error('播放音频失败',1);
        return;
      });
      isPlaying.value = true;
      currentPlayingType.value = 'main';
      currentAudio.value = audioElement.value;

    }
  };
  // 监听音量变化
  watch(volume, (newValue) => {
    if (audioElement.value) {
      audioElement.value.volume = newValue / 100;
    }
  });

  // 监听播放速度变化
  watch(speedNumber, (newValue) => {
    if (audioElement.value) {
      audioElement.value.playbackRate = newValue;
    }
  });

  // 下载音频
  const downloadAudio = () => {
    if (!hasAudio.value || !audioUrl.value ) {
      message.warning('没有可下载的音频',1);
      return;
    } 
if(isGenerating.value){
  message.warning('正在生成音频，请稍候...',1);
  return;
}
    const link = document.createElement('a');
    link.href = audioUrl.value;
    link.download = 'audio.' + outputFormat.value;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  };

  // 处理进度条变化
  const handleProgressChange = (value) => {
    if (!audioElement.value) return;
    const duration = audioElement.value.duration;
    const newTime = (value / 100) * duration;
    audioElement.value.currentTime = newTime;
    currentTime.value = formatTime(newTime);
    // 更新进度条显示
    progress.value = value;
  };
  //   // 播放系统声音的音频相关
  // 当前正在播放的音频实例

  // 预览音频播放
  const playPreviewAudio = async (voice) => {
    try {
      if (!voice.outputUrl) {
        message.warning('音频文件不存在',1);
        return;
      }

      // 如果当前正在播放这个音频，则切换播放状态
      if (currentPlayingId.value === voice.voiceId) {
        if (isPlaying.value) {
          stopAllAudio();
          return;
        }
      } else {
        // 如果要播放新的音频，先停止当前播放
        stopAllAudio();
      }

      // 初始化音频播放器
      if (!audioPlayer.value) {
        audioPlayer.value = new Audio();
        audioPlayer.value.addEventListener('ended', () => {
          stopAllAudio();
        });
      }

      // 设置新的音频源并播放
      audioPlayer.value.src = voice.outputUrl;
      await audioPlayer.value.play().catch(error => {
        console.error('播放音频失败:', error);
        message.error('播放音频失败',1);
        return;
      });

      // 更新播放状态
      isPlaying.value = true;
      currentPlayingId.value = voice.voiceId;
      currentPlayingType.value = 'preview';
      currentAudio.value = audioPlayer.value;
    } catch (error) {
      console.error('音频播放失败:', error);
      message.error('音频播放失败',1);
    }
  };

  // 组件卸载时清理音频播放器
  onUnmounted(() => {
    if (audioPlayer.value) {
      audioPlayer.value.pause();
      audioPlayer.value = null;
    }
  });

  // 导航栏的数据切换
  const tabs = [
    { key: 'voice', label: '音色' },
    { key: 'setting', label: '设置' },
    { key: 'history', label: '历史' }
  ];

  // 预设音色库
  const presetVoices = ref([]);
  const userVoices = ref([]);


  // 合并预设和用户音色用于展示
  const voices = computed(() => presetVoices.value);

  const isDropdownOpen = ref(false);
  const selectedVoiceId = ref('');
  const selectedVoice = ref('');
  // 下拉框选项只显示用户音色
  const voiceOptions = computed(() => userVoices.value.map(voice => voice.voiceName));

  const selectVoice = (voiceName) => {
    selectedVoice.value = voiceName;
    // 先在用户音色中查找，如果找不到再在预设音色中查找
    const selectedVoiceObj = userVoices.value.find(v => v.voiceName === voiceName) || 
                            presetVoices.value.find(v => v.voiceName === voiceName);
    selectedVoiceId.value = selectedVoiceObj ? selectedVoiceObj.id : '';
    isDropdownOpen.value = false;
  };

  const clearSelectedVoice = () => {
    selectedVoice.value = '';
    selectedVoiceId.value = '';
  };


  // 历史记录数据
  const historyRecords = ref([]);
  // 删除历史记录
  const handleDeleteHistory = async (id) => {
    try {
      await deleteHistory(id);
      message.success('删除成功',1);
      //重新获取历史记录的数据
      const response = await getHistory();
      historyRecords.value = response.data.list;
    } catch (error) {
      console.error('删除历史记录失败:', error);
    }
  };

  // 处理历史记录音频播放
  const handleHistoryAudioPlay = async (record) => {
    try {
      if (!record.audioUrl) {
        message.warning('音频文件不存在',1);
        return;
      }

      // 如果当前正在播放这个音频，则切换播放状态
      if (currentPlayingId.value === record.id) {
        if (isPlaying.value) {
          stopAllAudio();
          return;
        }
      } else {
        // 如果要播放新的音频，先停止当前播放
        stopAllAudio();
      }

      // 初始化音频播放器
      if (!audioPlayer.value) {
        audioPlayer.value = new Audio();
        audioPlayer.value.addEventListener('ended', () => {
          stopAllAudio();
        });
      }

      // 设置新的音频源并播放
      audioPlayer.value.src = record.audioUrl;
      await audioPlayer.value.play().catch(error => {
        console.error('音频播放失败:', error);
        message.error('音频播放失败',1);
        return;
      });

      // 更新播放状态
      isPlaying.value = true;
      currentPlayingId.value = record.id;
      currentPlayingType.value = 'history';
      currentAudio.value = audioPlayer.value;
    } catch (error) {
      console.error('音频播放失败:', error);
      message.error('音频播放失败',1);
    }
  };

  // 处理历史记录音频下载
  const handleHistoryDownload = (record) => {
    if (!record.audioUrl) {
      message.warning('音频文件不存在',1);
      return;
    }
    const link = document.createElement('a');
    link.href = record.audioUrl;
    link.download = `audio_${record.id}.${outputFormat.value}`;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  };


</script>
<style lang="scss" scoped>
  /* 主容器样式 */
  .tts-container {
    background-color: #f3f4f6;
    height: 90.1vh;
  }

  /* 在现有样式的最前面添加 */
  /* .mask {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 1000;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .loading-content {
    text-align: center;
  } */
  /* 内容包装器 */
  .content-wrapper {
    max-width: 90rem;
    min-height: 100%;
    margin: 0 auto;
    padding: 1rem 1.5rem;
    display: flex;
    gap: 1.5rem;
  }

  /* 左侧内容区 */
  .left-content {
    width: 66.666%;
    background-color: white;
    border-radius: 0.5rem;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
    padding: 1.5rem;
  }

  /* 头部区域 */
  .header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 1rem;
  }

  .title {
    font-size: 1.5rem;
    font-weight: 540;
  }

  .help-icon {
    color: #9ca3af;
    font-size: 1.125rem;
  }

  /* 文本输入区 */
  .text-input {
    height: 68%;
    margin-bottom: 1rem;
    font-size: 1rem;
        /* 自定义滚动条样式 */
    &::-webkit-scrollbar {
      width: 6px;

    }

    &::-webkit-scrollbar-track {
      background: #e5e5e5;
      border-radius: 3px;
    }

    &::-webkit-scrollbar-thumb {
      background: #e5e5e5;
      border-radius: 3px;

      &:hover {
        background: #b2b2b2;
      }
    }
  }

  /* 字数计数器 */
  .text-counter {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    margin-bottom: 1rem;
  }

  .counter {
    color: #9ca3af;
    font-size: 0.875rem;
  }

  /* 生成按钮区域 */
  .generate-button-wrapper {
    display: flex;
    justify-content: flex-start;
    margin-bottom: 1.5rem;
  }

  .generate-button {
    border-radius: 0.25rem;
    white-space: nowrap;
    border: none;
    transform: scale(1.3);
    transform-origin: center;
    margin: 0rem 1.2rem;
    padding: 0.4rem 1.5rem;
  }

  .disabled-button {
    opacity: 0.5;
    cursor: not-allowed;
    background-color: #f6f5f7;
  }

  /* 播放器控制区 */
  .player-controls {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 1rem;
    background-color: #f9fafb;
    border-radius: 0.5rem;
    margin-top: 2.5rem;
  }

  .player-left {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    height: 100%;
  }

  .play-pause-icon {
    font-size: 1.6rem;
    cursor: pointer;
    color: #000;

    &.disabled {
      color: #9ca3af;

      &:hover {
        color: #9ca3af;
      }
    }

    display: flex;
    align-items: center;

    &:hover {
      color: #2563eb;
    }
  }

  .time-display {
    color: #6b7280;
    font-size: 0.875rem;
  }

  .progress-bar {
    flex: 1;
  }

  .player-right {
    position: relative;
    display: flex;
    align-items: center;
    gap: 1rem;
  }

  /* 音量控制 */
  .volume-control {
    .disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }



    &:hover .volume-slider-container {
      opacity: 1;
      visibility: visible;
      transform: translateY(0);
    }
  }

  .volume-icon {
    font-size: 1.125rem;
    cursor: pointer;

    &:hover {
      color: #2563eb;
    }
  }

  .volume-slider-container {
    position: absolute;
    bottom: calc(100% + 0.7rem);
    /* left: 50%; */
    /* transform: translateX(-50%) translateY(10px); */
    right: 12%;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
    z-index: 20;
  }

  .volume-slider-wrapper {
    background-color: white;
    padding: 0.75rem 0.5rem;
    border-radius: 0.5rem;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    position: relative;

    &::after {
      content: '';
      position: absolute;
      bottom: -6px;
      left: 50%;
      transform: translateX(-50%) rotate(45deg);
      width: 12px;
      height: 12px;
      background-color: white;
      box-shadow: 4px 4px 15px rgba(0, 0, 0, 0.1);
    }
  }

  .volume-slider {
    height: 6rem;
  }

  .download-icon {
    font-size: 1.125rem;
    cursor: pointer;
    margin-bottom: .0875rem;

    &:hover {
      color: #2563eb;
    }

    &.disabled {
      color: #9ca3af;
      cursor: not-allowed;

      &:hover {
        color: #9ca3af;
      }
    }
  }

  /* 右侧边栏 */
  .right-sidebar {
    width: 33.333%;
  }

  /* 标签导航 */
  .tab-navigation {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    margin-bottom: 1.5rem;
    border-bottom: 1px solid #e5e7eb;
  }

  .tab-button {
    flex: 1;
    text-align: center;
    border-radius: 0.25rem;
    white-space: nowrap;
    padding-bottom: 0.5rem;
    position: relative;

    &:hover {
      color: #2563eb;
    }
  }

  .active-tab {
    color: #2563eb;
    position: relative;

    &::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 2px;
      background-color: #2563eb;
      transform: scaleX(1);
      transition: transform 0.3s ease-in-out;
    }
  }

  .inactive-tab {
    color: #6b7280;
    position: relative;

    &::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 2px;
      background-color: #2563eb;
      transform: scaleX(0);
      transition: transform 0.3s ease-in-out;
    }
  }

  /* 克隆声音横幅 */
  .voice-library-title {
    margin-bottom: 1rem;

    h3 {
      font-size: 1rem;
      font-weight: 500;
      color: #1f2937;
      margin-bottom: 0.5rem;
    }

    .empty-tip {
      font-size: 0.875rem;
      color: #6b7280;
    }
  }

  .clone-voice-banner {
    background: linear-gradient(to right, #3b82f6, #b39ce7);
    padding: 0.8rem;
    border-radius: 0.5rem;
    color: white;
    margin-bottom: 1rem;
  }

  .banner-title {
    font-size: 1.125rem;
    font-weight: 500;
    margin-bottom: 0.5rem;
  }

  .banner-description {
    font-size: 0.875rem;
    opacity: 0.8;
  }

  /* 音色下拉菜单 */
  .voice-dropdown-container {
    margin-bottom: 1.5rem;
    position: relative;
  }

  .voice-dropdown {
    width: 100%;

    &.selected {
      .dropdown-content {
        border-color: #2563eb;
      }
    }
  }

  .dropdown-content {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0.5rem 1rem;
    background-color: #f9fafb;
    border: 1.5px solid #e5e7eb;
    border-radius: 0.5rem;
    cursor: pointer;

    &:hover {
      border-color: #2563eb;
    }
  }

  .dropdown-icons {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }

  .clear-icon {
    color: #9ca3af;
    font-size: 1rem;
    transition: color 0.3s;

    &:hover {
      color: #ef4444;
    }
  }

  .dropdown-text {
    color: #6b7280;
  }

  .rotate-icon {
    transform: rotate(180deg);
    transition: transform 0.3s;
  }

  .dropdown-options {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background-color: white;
    border: 1px solid #e5e7eb;
    border-radius: 0.5rem;
    margin-top: 0.5rem;
    max-height: 12rem;
    overflow-y: auto;
    z-index: 10;
  }

  .dropdown-option {
    padding: 0.5rem 1rem;
    cursor: pointer;

    &:hover {
      background-color: #e6f4ff;
    }

    .option-content {
      display: flex;
      flex-direction: column;
      gap: 0.25rem;
    }

    .option-text {
      font-size: 0.875rem;
      color: #1f2937;
    }


  }

  .empty-option {
    color: #9ca3af;
    cursor: default;

    &:hover {
      background-color: transparent;
    }
  }

  /* 音色库标题 */
  .voice-library-title {
    margin-bottom: 1rem;

    h3 {
      font-size: 1rem;
      font-weight: 500;
      color: #1f2937;
      margin-bottom: 0.5rem;
    }

    .empty-tip {
      font-size: 0.875rem;
      color: #6b7280;
    }
  }

  /* 设置模块 */
  .setting-module {

    .setting-section {
      margin-bottom: 1.5rem;
      padding: 1rem;
      border-radius: 0.5rem;

      .section-title {
        font-size: 1rem;
        font-weight: 500;
        color: #1f2937;
        margin-bottom: 1rem;
      }
    }

    .setting-item {
      display: flex;
      align-items: center;
      margin-bottom: 1rem;

      &:last-child {
        margin-bottom: 0;
      }

      .speed-control {
        display: flex;
        flex-direction: column;
        gap: 1rem;
        width: 100%;

        .speed-header {
          display: flex;
          justify-content: space-between;
          align-items: center;
          margin-bottom: 0.5rem;
        }

        .speed-title {
          display: flex;
          align-items: center;
          gap: 0.5rem;
        }

        .speed-value {
          color: #6b7280;
        }

      }

      .custom-slider {
        margin-left: 15px;
        width: 90%;

        :deep(.ant-slider-track) {
          background: linear-gradient(90deg, #4f83f1 0%, #2563eb 100%);
        }

        :deep(.ant-slider-mark-text) {
          color: #666;
          font-size: 12px;
        }

        :deep(.ant-slider-mark-text-active) {
          color: #2563eb;
        }

        :deep(.ant-slider-handle) {
          border-color: #2563eb;

          &:hover {
            border-color: #2563eb;
          }
        }
      }

      .setting-label {
        margin-right: 8px;
      }

      .setting-select {
        flex: 1;
      }
    }
  }

  /* 历史记录模块 */
  .history-module {
    width: 455px;
    min-width: 455px;
    .history-list {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 0.75rem;
      height: 730px;
      overflow-y: auto;
      padding-right: 6px;

      /* 自定义滚动条样式 */
      &::-webkit-scrollbar {
        width: 6px;
      }

      &::-webkit-scrollbar-track {
        background: #e5e5e5;
        border-radius: 3px;
      }

      &::-webkit-scrollbar-thumb {
        background: #e5e5e5;
        border-radius: 3px;

        &:hover {
          background: #b2b2b2;
        }
      }
    }

    .history-item {
      width: 96%;
      background-color: #fff;
      border-radius: 0.5rem;
      padding: 1rem;
      box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
      border: 1.5px solid transparent;
      display: flex;
      justify-content: space-between;
      align-items: center;
      transition: border-color 0.3s ease;

      &:hover {
        border-color: #2563eb;
      }

      .history-content {
        flex: 1;
        min-width: 0;

        .history-text {
          max-width: 95%;
          font-size: 0.875rem;
          color: #1f2937;
          margin-bottom: 0.5rem;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }

        .history-info {
          display: flex;
          gap: 1rem;
          font-size: 0.75rem;
          color: #6b7280;

          .history-time {
            white-space: nowrap;
          }

          .history-voice {
            white-space: nowrap;
          }
        }
      }

      .history-actions {
        display: flex;
        gap: 0.75rem;
        margin-left: 1rem;

        .history-action-icon {
          font-size: 1.3rem;
          color: #6b7280;
          cursor: pointer;

          &:hover {
            color: #2563eb;
          }
        }

        .delete {
          font-size: 1.3rem;
          color: #6b7280;
          cursor: pointer;

          &:hover {
            color: #f5222d;
          }
        }
      }
    }
  }

  /* 音色卡片网格 */
  .voice-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.8rem;
    height: 485px;
    overflow-y: auto;
    padding-right: 4px;
    /* margin-left: 4px; */

    /* 自定义滚动条样式 */
    &::-webkit-scrollbar {
      width: 6px;

    }

    &::-webkit-scrollbar-track {
      background: #e5e5e5;
      border-radius: 3px;
    }

    &::-webkit-scrollbar-thumb {
      background: #e5e5e5;
      border-radius: 3px;

      &:hover {
        background: #b2b2b2;
      }
    }
  }

  .voice-card {
    position: relative;
    border-radius: 0.5rem;
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.3s;
    height: 70px;
    margin-left: 2px;
    margin-top: 4px;

    /* &:hover {
      transform: translateY(-2px);
    } */
  }

  .card-content {
    position: relative;
    z-index: 1;
    padding: 0.5rem;
    color: white;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
  }

  .selected-badge {
    position: absolute;
    top: 0.25rem;
    right: 0.25rem;
    background-color: #1677ff;
    color: white;
    padding: 0.125rem 0.375rem;
    border-radius: 0.25rem;
    font-size: 0.75rem;
  }
 
  .voice-name {
    font-size: 0.85rem;
    font-weight: 500;
    margin-bottom: 0.5rem;
    /* color: #323538; */
    position: relative;
    z-index: 1;
  }

 

  .play-button {
    position: absolute;
    right: 0.5rem;
    bottom: 0.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    transition: background-color 0.3s;

    &:hover {
      background-color: rgba(255, 255, 255, 0.3);
    }
  }

  .play-icon {
    font-size: 1.25rem;
    color: white;
  }

  .card-background {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
 
  }

  .card-content {
    position: relative;
    background-color: rgba(255, 255, 255, 0.226);
    border-radius: 8px;
    padding: 1rem;
    z-index: 1;
  }

  .selected-voice {
    box-shadow: 0 0 0 2px #2b6af3;
  }
</style>